package com.example.dig.util;

import com.example.dig.model.Animal;
import com.example.dig.model.User;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

import java.io.IOException;
import java.io.OutputStream;
import java.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author ZH
 */
public class ExcelExporter {

    public static void main(String[] args) throws IOException {
        List<User> users = new ArrayList<>();
        users.add(new User("张三", 20, 1, "足球"));
        users.add(new User("李四", 18, 0, "羽毛球"));
        users.add(new User("王五", 65, 1, "跑步"));
        users.add(new User("赵六", 32, 1, "游戏"));

        OutputStream outputStream = Files.newOutputStream(Paths.get("export/users.xlsx"));
        ExcelExporter.export(users,outputStream);


        List<Animal> animals = new ArrayList<>();
        animals.add(new Animal("金丝猴",5,true));
        animals.add(new Animal("大熊猫",2,true));
        animals.add(new Animal("河马",8,false));
        animals.add(new Animal("灰狼",23,false));

        OutputStream outputStream2 = Files.newOutputStream(Paths.get("export/animals.xlsx"));
        ExcelExporter.export(animals,outputStream2);

        int[] arr = new int[]{1,5,6,4,8,25,12,75,35,1,2,15,42,100,10};
        int[] resArr = bubbleSort(arr);
        System.out.println(Arrays.toString(resArr));

        int[] ascArr = new int[]{11, 22, 33, 44, 55, 66, 77, 88, 99};
        int value = 100;
        int index = halfSearch(ascArr, 0, ascArr.length - 1, value);
        System.out.println("value = "+value+" index = "+index);

    }

    public static void export(List<?> t, OutputStream outputStream) {
        if(t == null || t.size() < 1 ){
            System.out.println("参数不合法, t == null || t.size() < 1 "+t);
            return;
        }
        if(outputStream == null){
            System.out.println("outputStream == null");
            return;
        }
        try {
            XSSFWorkbook workbook = new XSSFWorkbook();
            XSSFSheet sheet = workbook.createSheet();

            //获取所有包含Excel注解的字段
            Field[] fields = t.get(0).getClass().getDeclaredFields();
            if (fields == null || fields.length < 1) {
                System.out.println("fields获取失败：  fields == null || fields.length < 1");
                return;
            }
            List<Field> fieldList = Arrays.stream(fields)
                    .filter(f -> f.isAnnotationPresent(Excel.class))
                    .collect(Collectors.toList());
            if(fieldList == null || fieldList.size() < 1){
                System.out.println("fieldList获取失败：  fieldList == null || fieldList.size()");
                return;
            }

            //写入标题行
            writeTitleRow(sheet,fieldList);

            //写入数据行
            for (int i = 0; i < t.size(); i++) {
                Row row = sheet.createRow(i + 1);
                writeRowData(t.get(i), row, fieldList);
            }

            //保存数据到文件
            workbook.write(outputStream);
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    /**
     * 写入Excel表格的标题行
     * @param sheet excel页面编辑器
     * @param fieldList 实体类中所有带Excel注解声明的字段
     */
    private static void writeTitleRow(XSSFSheet sheet, List<Field> fieldList) {
        Row row = sheet.createRow(0);
        for (int i = 0; i < fieldList.size(); i++) {
            Cell cell = row.createCell(i);
            Excel excel = fieldList.get(i).getAnnotation(Excel.class);
            cell.setCellValue(excel.name());
        }
    }

    /**
     * 写入Excel表格的内容
     * @param obj 实体类（数据类）
     * @param row 数据行
     * @param fieldList 实体类中所有带Excel注解声明的字段
     * @throws IllegalAccessException
     */
    private static void writeRowData(Object obj, Row row, List<Field> fieldList) throws IllegalAccessException {
        Map<Field, Map<String, String>> fieldDect = buildFieldDect(fieldList);
        for (int i = 0; i < fieldList.size(); i++) {
            Cell cell = row.createCell(i);
            Field field = fieldList.get(i);
            field.setAccessible(true);
            Excel annotation = field.getAnnotation(Excel.class);
            if (!"".equals(annotation.dictValue())) {
                String key = String.valueOf(field.get(obj));
                String value = fieldDect.get(field).get(key);
                cell.setCellValue(value);
            }else {
                cell.setCellValue(String.valueOf(field.get(obj)));
            }
            field.setAccessible(false);
        }
    }

    /**
     * 解析Excel注解中dictValue信息并储存
     * @param fieldList 实体类中所有带Excel注解声明的字段
     * @return Map<Field, Map<String, String>> Field：实体类的字段（注解中带有dictValue值）
     *                                         Map<String, String>: dictValue值
     */
    private static Map<Field, Map<String, String>> buildFieldDect(List<Field> fieldList) {
        Map<Field, Map<String, String>> fieldDect = new HashMap<>(16);
        for (Field field : fieldList) {
            Excel annotation = field.getAnnotation(Excel.class);
            if(!"".equals(annotation.dictValue())){
                String dict = annotation.dictValue();
                String[] split = dict.split(",");
                Map<String, String> map = new HashMap<>(16);
                for (String s : split) {
                    String[] kv = s.split("=");
                    map.put(kv[0], kv[1]);
                }
                fieldDect.put(field,map);
            }
        }
        return fieldDect;
    }




    /**
     * 从小到大 冒泡排序
     * @param arr 待排序数组
     * @return 排序结果
     */
    public static int[] bubbleSort (int[] arr){
        if(arr == null || arr.length < 1){
            System.out.println("数组不合法");
            return arr;
        }
        int temp = 0;
        //第一个for循环定义循环次数
        for (int i = 0; i < arr.length - 1; i++) {
            //第二个for循环比较相邻两个数的值，大数在后
            for(int j = 0; j < arr.length - i - 1 ; j++){
                if (arr[j] > arr[j+1]) {
                    temp = arr[j];
                    arr[j] = arr[j+1];
                    arr[j+1] = temp;
                }
            }
        }
        return arr;
    }

    /**
     * 二分查找算法
     * @param ascArr 目标数组（已排序 升序 asc）
     * @param start 数组起始索引
     * @param end 数组终止索引
     * @param value 搜索值
     * @return 搜索结果
     */
    public static int halfSearch (int[] ascArr, int start, int end, int value) {
        System.out.println("start = "+start+" end = "+end+" value = "+value);
        int length = ascArr.length;
        if (ascArr == null || length < 1) {
            System.out.println("数组不合法");
            return -1;
        }
        if(value < ascArr[start] || value > ascArr[end]){
            System.out.println(value+"不在数组中");
            return -1;
        }
        if(start < 0 || start > length -1){
            System.out.println("start error!  start:"+start);
            return -1;
        }
        if(end < 0 || end > length -1){
            System.out.println("end error!  end:"+end);
            return -1;
        }

        if(start > end){
            System.out.println("start or end error! start:"+start+" end:"+end+" arr:"+Arrays.toString(ascArr));
            return -1;
        }

        int mid = (start + end) / 2;
        if(value == ascArr[mid]){
            System.out.println("mid = " + mid);
            return mid;
        }else if (value < ascArr[mid]) {
            return halfSearch(ascArr, start, mid - 1, value);
        }else{
            return halfSearch(ascArr, mid + 1, end, value);
        }
    }
}
